/*
    This file is part of Emu.

    Emu is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Emu is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Emu.  If not, see <http://www.gnu.org/licenses/>. */
#ifndef ESESSION_H
# define ESESSION_H

# include <QSplitter>
# include <QTcpSocket>
# include <QTextCharFormat>
# include <QTextCursor>
# include <QLineEdit>

# include "eprofile.h"
# include "esplitter.h"

enum ESocketState {
    SocketNeverConnected, /* Never connected anywhere. */
    SocketConnected,      /* Currently connected. */
    SocketDisconnected    /* Connected at some point, but dropped. */
};

class ESession : public QObject
{
    Q_OBJECT

public:
    ESession(EProfile *);
    ~ESession();

    ESocketState socketState() { return _socketState; }
    QString logfilePath() { return _logfilePath; }
    QTextEdit *recvWindow() { return _recvWindow; }
    ETextEdit *sendWindow() { return _sendWindow; }
    QLineEdit *searchWindow() { return _searchWindow; }
    ESearchBar *searchBar() { return _searchBar; }

    ESplitter *splitter() { return _splitter; }
    EProfile *profile() { return _profile; }

    void resetAppearance(bool [32]);
    void save(QString);
    void setCurrent(bool c) { _current = c; _searchBar->setCurrent(c); }
    void start();
    void writeMessage(QString);

private:
    ESocketState _socketState;

    enum AnsiState {
        AnsiText,      /* Outside of any code. */
        AnsiNeedBrace, /* Have ESC, need [. */
        AnsiValue      /* Need numbers, semicolons, or a finishing letter. */
    } _ansiState;

    enum TelnetState {
        TelnetText,        /* Outside of telnet. */
        TelnetStart,       /* Found opening IAC. */
        TelnetOption,      /* Need an option code (comes after will/will not/
                              do/dont) */
        TelnetSubnegStart, /* About to start subnegotiation. */
        TelnetSubneg       /* Within subnegotiation. */
    } _telnetState;

    /* If true, then SE will end the current subnegotation. */
    bool _telnetEscapeOnSE;

    bool _current;
    /* TRUE if this session is the current one. */

    bool _textSent;
    int _inputIndex;
    char *_inputBuffer;
    /* This holds the initial input. */

    int _ansiBufferIndex;
    char _ansiBuffer [4096];
    /* This holds initial input, minus telnet. For ansi processing. */

    int _textIndex;
    char _textBuffer [4096];
    /* Initial input, minus telnet and ansi. This is used first for matching
       triggers. Afterwards, ansi parsing will place text here from in between
       ansi codes (for printing). */

    QList <int> _ansiCodeList;
    int _ansiCurrentCode;
    int _ansiAdjust;
    int _ansiAttributes;

    QLineEdit *_searchWindow;
    ESearchBar *_searchBar;
    QTextEdit *_recvWindow;
    EProfile *_profile;
    ETextEdit *_sendWindow;

    QString _logfilePath;
    ESplitter *_splitter;
    QTcpSocket *_socket;
    QTextCharFormat _recvFormat;
    QTextCursor _recvCursor;

    bool eventFilter(QObject *, QEvent *);
    void executeAnsi();
    void processAnsi(bool);
    bool processTriggers();
    void processTelnet();
    void updateDisplay();

private slots:
    void readyRead();
    void disconnected();
    void error(QAbstractSocket::SocketError);
    void connected();

Q_SIGNALS:
    void focusChanged();
};

#endif

